﻿using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Diagnostics;

namespace Kyoh.Lib.Component
{
    /// <summary><see cref="Type"/> と <see cref="String"/> を相互変換する <see cref="TypeConverter"/> の実装。</summary>
    public class TypeNameConverter : TypeConverter
    {
        /// <summary>指定された型から変換可能であるかどうかを取得します。</summary>
        /// <param name="context">変換する型を表す <see cref="ITypeDescriptorContext"/> インターフェースのオブジェクト。</param>
        /// <param name="sourceType">変換する型を表す ><see cref="Type"/>。</param>
        /// <returns>変換可能な場合は <c>true</c> 、それ以外の場合は <c>false</c> 。</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            Debug.WriteLine(sourceType);
            return sourceType == typeof(Type) || sourceType == typeof(string);
        }

        /// <summary>指定された型へ変換可能であるかどうかを取得します。</summary>
        /// <param name="context">変換する型を表す <see cref="ITypeDescriptorContext"/> インターフェースのオブジェクト。</param>
        /// <param name="destinationType">変換する型を表す ><see cref="Type"/>。</param>
        /// <returns>変換可能な場合は <c>true</c> 、それ以外の場合は <c>false</c> 。</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            Debug.WriteLine(destinationType);
            return destinationType == typeof(string) || destinationType == typeof(Type);
        }

        /// <summary>文字列をオブジェクトに変換します。</summary>
        /// <param name="context">変換する型を表す <see cref="ITypeDescriptorContext"/> インターフェースのオブジェクト。</param>
        /// <param name="culture">変換に使用するカルチャを表す <see cref="System.Globalization.CultureInfo"/>。</param>
        /// <param name="value">変換するオブジェクト。</param>
        /// <returns>変換したオブジェクト。</returns>
        [MethodImpl(MethodImplOptions.NoInlining)]
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value == null)
                return null;

            Type type = value as Type;
            string typeName = value as string;
            if (type != null)
                return type;
            else if (string.IsNullOrEmpty(typeName))
            {
                System.IO.File.WriteAllText(@"test.txt", string.Format("ConvertFrom1(value: {0})", value));
                throw new NotSupportedException();
            }
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = assembly.GetType(typeName, false);
                if (type != null)
                    return type;
            }
            System.IO.File.WriteAllText(@"test.txt", string.Format("ConvertFrom2(value: {0})", value));
            throw new NotSupportedException();
        }

        /// <summary>オブジェクトを指定された型に変換します。</summary>
        /// <param name="context">変換先の型を表す <see cref="ITypeDescriptorContext"/> インターフェースのオブジェクト。</param>
        /// <param name="culture">変換に使用するカルチャを表す <see cref="System.Globalization.CultureInfo"/>。</param>
        /// <param name="value">変換するオブジェクト。</param>
        /// <param name="destinationType">変換先の型。</param>
        /// <returns>変換したオブジェクト。</returns>
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(Type))
                return ConvertFrom(context, culture, value);

            if (destinationType != typeof(string))
                throw new NotSupportedException();
            if (value == null)
                return null;

            Type type = value as Type;
            string typeName = value as string;
            if (typeName != null)
                return typeName;
            if (type == null)
                throw new NotSupportedException();
            else
                return type.FullName;
        }
    }
}
